#pragma once

#include <iostream>
#include <filesystem>
#include <memory>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>

/*client 发送给 server 的输⼊内容，拼接上时间，进程pid信息
• server 收到的内容持久化保存到⽂件中
• ⽂件的内容如果过⼤，要进⾏切⽚保存并在指定的⽬录下打包保存，命令⾃定义*/

// 路径
const std::string gfilepath = "./tmp/";
// 文件名
const std::string gfilename = "log.txt";

// 最大行
const int gline_max = 2;

// 基类
class HandlerText
{
public:
    HandlerText(bool enable = true)
        : _enable(enable),
          _next_handler(nullptr)
    {
    }

    void Next(std::shared_ptr<HandlerText> next)
    {
        _next_handler = next;
    }

    void Enable() { _enable = true; }
    void DisEnable() { _enable = false; }
    bool IsEnable() { return _enable; }
    virtual void Execute(std::string &info) = 0;

    virtual ~HandlerText()
    {
    }

protected: // 这⾥要protected，⽅便继承
    std::shared_ptr<HandlerText> _next_handler;
    bool _enable;
};

// client 发送给 server 的输⼊内容，拼接上时间，进程pid信息 -- 封装
class HandlerWrap : public HandlerText
{
public:
    HandlerWrap()
    {
    }
    void Execute(std::string &info)
    {

        if (IsEnable())
        {
            std::cout << "进入封装环节" << std::endl;
            // 获取时间搓和pid
            int t = (time(nullptr));
            int pid = getpid();

            // 进行拼接
            info = info + "-" + std::to_string(t) + "-" + std::to_string(pid) + "\n";

            std::cout << "拼接完成" << std::endl;
        }

        if (_next_handler != nullptr)
        {
            std::cout << "准备进入保存文件" << std::endl;
            _next_handler->Execute(info);
        }
        else
        {
            std::cout << "责任链完成" << std::endl;
        }
    }
    ~HandlerWrap()
    {
    }
};

class HandelerSaveFile : public HandlerText
{
public:
    HandelerSaveFile(std::string filepath = gfilepath, std::string filename = gfilename)
        : _filepath(filepath),
          _filename(filename)
    {
        if (std::filesystem::exists(_filepath))
        {
            return;
        }

        // 不存在当前目录 - 创建目录
        try
        {
            std::filesystem::create_directories(_filepath);
        }
        catch (const std::filesystem::filesystem_error &e)
        {
            std::cerr << e.what() << '\n';
        }

        std::cout << "完成创建目录" << std::endl;
    }

    void Execute(std::string &info)
    {

        if (IsEnable())
        {
            std::cout << "进入保存环节" << std::endl;
            std::string url = _filepath + _filename;
            std::fstream file(url, std::ios::app);

            if (!file.is_open())
            {
                std::cout << "打开文件失败" << std::endl;
                return;
            }

            file << info;

            file.close();
            std::cout << "保存完成" << std::endl;
        }

        if (_next_handler != nullptr)
        {
            std::cout << "准备进入备份" << std::endl;
            _next_handler->Execute(info);
        }
        else
        {
            std::cout << "责任链完成" << std::endl;
        }
    }

    ~HandelerSaveFile()
    {
    }

private:
    std::string _filepath;
    std::string _filename;
};

class HandelerBackupFile : public HandlerText
{
public:
    HandelerBackupFile(std::string filepath = gfilepath, std::string filename = gfilename,
                       int line_max = gline_max)
        : _filepath(filepath),
          _filename(filename),
          _line_max(line_max)

    {
    }

    void Execute(std::string &info)
    {

        if (IsEnable())
        {
            std::cout << "进入备份环节" << std::endl;
            // 行数
            int line = Iine();
            std::cout<<line<<std::endl;

            if(line >= _line_max)
            {
                std::cout<<"进行备份打包"<<std::endl;
                Backup();
                std::cout << "备份完成" << std::endl;
            }
            else
            {
                std::cout << "不需要备份" << std::endl;
            }

        }

        if (_next_handler != nullptr)
        {
            std::cout << "准备进入..." << std::endl;
            _next_handler->Execute(info);
        }
        else
        {
            std::cout << "责任链完成" << std::endl;
        }
    }
    ~HandelerBackupFile()
    {
    }

private:
    int Iine()
    {
        const std::string filename = _filepath + _filename;
        // 1. 打开⽂件
        std::ifstream in(filename);
        if (!in.is_open())
            return -1;

        std::string line;
        int currentlines = 0;
        while (std::getline(in, line))
        {
            currentlines++;
        }
        // 关闭⽂件流
        in.close();

        return currentlines;
    }

    void Backup()
    {
        pid_t id = ::fork();
        //获取新的文件名
        std::string newname = _filename + "." + std::to_string(time(nullptr));
        //子进程
        if(id == 0)
        {
            //更改当前路径
            ::chdir(_filepath.c_str());

            //更换文件名
            std::filesystem::rename(_filename, newname);

            //进行打包
            std::string tarname = newname + ".tgz";
            execlp("tar", "tar", "czf", tarname.c_str(), newname.c_str(),nullptr);

            exit(0);
        }

        int n = ::waitpid(id,nullptr,0);
        if(n < 0)
        {
            std::cout<<"waitpid error"<<std::endl;
            return;
        }
        std::cout<<"waitpid succeed"<<std::endl;

        //删除原文件
        std::string filename = _filepath + newname;
        std::filesystem::remove(filename);
    }

private:
    int _line_max;
    std::string _filepath;
    std::string _filename;
};

class HandlerEntry
{
public:
    HandlerEntry()
    {
        // 构建责任链节点对象
        _format = std::make_shared<HandlerWrap>();
        _save = std::make_shared<HandelerSaveFile>();
        _backup = std::make_shared<HandelerBackupFile>();
        // 链接责任链
        _format->Next(_save);
        _save->Next(_backup);
    }
    void EnableHandler(bool isformat, bool issave, bool isbackup)
    {
        isformat ? _format->Enable() : _format->DisEnable();
        issave ? _save->Enable() : _save->DisEnable();
        isbackup ? _backup->Enable() : _backup->DisEnable();
    }
    void Run(std::string &info)
    {
        _format->Execute(info);
    }

private:
    std::shared_ptr<HandlerText> _format;
    std::shared_ptr<HandlerText> _save;
    std::shared_ptr<HandlerText> _backup;
};
